//
// Created by daiyi on 2019/09/30.
//

#include "stats.h"

#include <cassert>
#include <cmath>
#include <dirent.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <x86intrin.h>

#include "plr.h"
#include "util.h"
#include <numeric>

// 从路径中解析出数据名称
std::string get_dataname_from_filepath(std::string input_filename, std::string delimiter) {
  size_t pos = 0;
  std::string token;
  std::string data_name = input_filename;
  while ((pos = data_name.find(delimiter)) != std::string::npos) {
//    token = data_name.substr(0, pos);
//    std::cout << token << std::endl;
    data_name.erase(0, pos+delimiter.length());
  }
  delimiter = ".";
  data_name = data_name.substr(0, data_name.find(delimiter));
  return data_name;
}


// 这里是统计sstable的代码
int readFileList(char *basePath, std::string data_name, int mod, std::string executable_file, int iteration, int key_size)
{
  // 第一步，把所有的文件读成vector
  std::vector<std::string> result;
  DIR *dir;
  struct dirent *ptr;

  if ((dir=opendir(basePath)) == NULL)
  {
    perror("Open dir error...");
    exit(1);
  }

  while ((ptr=readdir(dir)) != NULL)
  {
    if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0)    ///current dir OR parrent dir
      continue;
    else if(ptr->d_type == 8)    ///file
    {
      result.push_back(std::string(ptr->d_name));
    }
    else if(ptr->d_type == 10)    ///link file
    {
      result.push_back(std::string(ptr->d_name));
    }
    else throw "no sub directories should appear";
  }
  closedir(dir);

  // 第二步，将vector保存到本地文件
  std::string out_path;
  if (mod==7) {
    out_path = "../runlogs/" + data_name + "_" + executable_file + "_" + std::to_string(key_size) + "_llsm_" + "iter" + std::to_string(iteration) + ".txt";
  } else {
    out_path = "../runlogs/" + data_name + "_" + executable_file + "_" + std::to_string(key_size) + "_baseline_" + "iter" + std::to_string(iteration) + ".txt";
  }
  std::ofstream fout(out_path);
  if (fout.is_open()) {
    for (vector<std::string>::iterator i=result.begin(), end=result.end(); i!=end; ++i) {
      fout << (*i);
      fout << '\n';
    }
  }
  fout.close();
  return 0;
}

// 统计时间的，一到这里
void perf_exclude_1st_Iteration(std::vector<std::vector<size_t>> times) {
  for (int s=0; s<times.size(); ++s) {
    std::vector<uint64_t>& time = times[s];
    std::vector<double> diff(time.size());
    if (time.empty()) continue;

    double sum = std::accumulate(time.begin(), time.end(), 0.0);
    double mean = sum / (time.size());
    std::transform(time.begin(), time.end(), diff.begin(), [mean] (double x) {return x-mean;});
    double stdev = std::sqrt(std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0) / time.size());

    printf("Timer %d MEAN: %lu, STDDEV: %f\n", s, (uint64_t) mean, stdev);
  }
}

int get_read_nums(std::vector<char> ops) {
  int cnt = 0;
  for (int i=0; i<ops.size(); i++) {
    if (ops[i] == 'R') {
      cnt += 1;
    }
  }
  return cnt;
}


// 这是作者原来的代码
using std::stoull;

namespace adgMod {

    // 对应博客说的，类中静态成员变量的初始化必须在类外实现
    Stats* Stats::singleton = nullptr;

    Stats::Stats() : timers(20, Timer{}), initial_time(__rdtsc()) {
        levelled_counters[0].name = "LevelModel";
        levelled_counters[1].name = "FileModel";
        levelled_counters[2].name = "Baseline";
        levelled_counters[3].name = "Succeeded";
        levelled_counters[4].name = "FalseInternal";
        levelled_counters[5].name = "Compaction";
        levelled_counters[6].name = "Learn";
        levelled_counters[7].name = "SuccessTime";
        levelled_counters[8].name = "FalseTime";
        levelled_counters[9].name = "FilteredLookup";
        levelled_counters[10].name = "PutWait";
        levelled_counters[11].name = "FileLearn";
    }

    Stats* Stats::GetInstance() {
        // 公有的函数，可以获取这个唯一的实例，并且在需要的时候创建该实例
        if (!singleton) singleton = new Stats();
        return singleton;
    }

    void Stats::StartTimer(uint32_t id) {
        Timer& timer = timers[id];  // id用来确定使用timers向量中哪个timer
        timer.Start();
    }

    std::pair<uint64_t, uint64_t> Stats::PauseTimer(uint32_t id, bool record) {
        Timer& timer = timers[id];
        return timer.Pause(record);
    }

    void Stats::ResetTimer(uint32_t id) {
        Timer& timer = timers[id];
        timer.Reset();
    }

    uint64_t Stats::ReportTime(uint32_t id) {
        Timer& timer = timers[id];
        return timer.Time();
    }

    void Stats::ReportTime() {
        for (int i = 0; i < timers.size(); ++i) {
            printf("Timer %u: %lu\n", i, timers[i].Time());
        }
    }

    uint64_t Stats::GetTime() {
        unsigned int dummy = 0;
        uint64_t time_elapse = __rdtscp(&dummy) - initial_time;
        return time_elapse / reference_frequency;
    }


    void Stats::ResetAll() {
        for (Timer& t: timers) t.Reset();
        for (Counter& c: levelled_counters) c.Reset();
        for (vector<Event*>& event_array : events) {
            for (Event* e : event_array) delete e;
            event_array.clear();
        }
        initial_time = __rdtsc();
    }

    Stats::~Stats() {
        ReportTime();
    }

}